﻿#include <stdio.h>
#include <string.h>
#include <fstream>

#include <QImage>
#include <opencv2/opencv.hpp>

#include "ImageView.h"

void ImageView::setImageList()
{
    std::ifstream inf(fileName.c_str());
    if (!inf.is_open())
    {
        printf("Images' list file not exist!\n");
        exit(-1);
    }
    
    std::string tmpfile;
    inf >> tmpfile;
    while (!inf.eof()) {
        ++totalLine;
        imageName.push_back(tmpfile);
        inf >> tmpfile;
    }
    inf.close();
}

void ImageView::setImage(void)
{
    std::string tmpName = prefix;
    tmpName += imageName[currentIndex];

    emit changeWindowName(QString::fromStdString(imageName[currentIndex]));
    cv::Mat currentImage = cv::imread(tmpName);
    emit read2refresh(currentImage);
    if (curImage.empty()) {
        return;
    }
    QImg = QImage(curImage.data,curImage.cols,curImage.rows,
                  curImage.step,QImage::Format_RGB888).rgbSwapped();
}

void ImageView::loadSetting(char *fileName_)
{
    for (int var = 0; var < 30; ++var) {
        printf("**");
    }
    printf("\n");

    m_config = new ParameterReader(fileName_);

    /// 0 fname_objClassDef
    std::string fname_objClassDef;
    if(m_config->getData("classify_file",fname_objClassDef)){
        printf("Set classify_file = %s!\n",fname_objClassDef.c_str());
    }
    else{
        printf("Warnning: without classify_file setting!"
               "\n\tUse default: \"AnoObjectDefines.cfg\" !\n");
        fname_objClassDef = "AnoObjectDefines.cfg";
    }
    load_anoObjClassList(fname_objClassDef, m_ocl);

    /// 1 fileName
    std::string tempSetting;
    if(m_config->getData("fileName",fileName)){
        printf("Set fileName = %s!\n",fileName.c_str());
    }
    else{
        printf("Warnning: without filename setting!"
               "\n\tUse default: \"file.txt\" !\n");
        fileName = "file.txt";
    }

    /// 2 data_dir
    if(m_config->getData("data_directory",prefix)){
       if (prefix.substr(prefix.size()-1, prefix.size())!=std::string("/"))
           prefix+="/";
        printf("Set data dir = %s!\n",prefix.c_str());
    }
    else{
        printf("Warnning: without data directory setting!"
               "\n\tUse default: \"data/image\" !\n");
        prefix = std::string("data/image/");
    }
    /// 3 result_dir
    if(m_config->getData("result_directory", resultDir)){
        if(resultDir.substr(resultDir.size()-1, resultDir.size()) != std::string("/"))
            resultDir+="/";
        printf("Set result dir = %s!\n", resultDir.c_str());
    }
    else{
        printf("Warnning: without result directory setting!"
               "\n\tUse default: \"data/result\" !\n");
        resultDir = std::string("data/result/");
    }

    /// 4 IMAGE_WIDTH
    if (m_config->getData("IMAGE_WIDTH", tempSetting)){
        printf("Set IMAGE_WIDTH = %s!\n", tempSetting.c_str());
        IMAGE_WIDTH = atoi(tempSetting.c_str());
    } else {
        printf("Warnning: without IMAGE_WIDTH setting!"
               "\n\tUse default: \"1280\" !\n");
        IMAGE_WIDTH = 1280;
    }
    /// 5 IMAGE_HEIGHT
    if(m_config->getData("IMAGE_HEIGHT",tempSetting)){
        printf("Set IMAGE_HEIGHT = %s!\n",tempSetting.c_str());
        IMAGE_HEIGHT = atoi(tempSetting.c_str());
    }
    else{
        printf("Warnning: without IMAGE_WIDTH setting!"
               "\n\tUse default: \"720\" !\n");
        IMAGE_HEIGHT = 720;
    }

    for (int var = 0; var < 30; ++var) {
        printf("**");
    }
    printf("\n\n\n");
}



ImageView::ImageView(char *fileName_,QWidget *parent)
    :QWidget(parent),currentIndex(0),currentType(0),m_config(NULL),
      needReload(true),selected(false),showAll(false),totalLine(0)
{
    loadSetting(fileName_);
    setImageList();

    connect(this, SIGNAL(read2refresh(cv::Mat&)), this, SLOT(Refresh(cv::Mat&)));
    lt = QPoint(0, 0);
    rb = QPoint(0, 0);

    std::string tmpName = prefix;
    tmpName += imageName[0];
    cv::Mat checkResolution = cv::imread(tmpName);
    if(checkResolution.empty()){
        printf("Error in load images, please check: \n\timages are in directory[%s]!\n",prefix.c_str());
        exit(-1);
    }
    if (checkResolution.cols != IMAGE_WIDTH || checkResolution.rows != IMAGE_HEIGHT) {
        printf("Error in images' Resolution with Window's Resolution,\n\tplease check :"
               "image are [%d*%d], but Windos is [%d*%d]!\n",
               checkResolution.cols,checkResolution.rows,IMAGE_WIDTH,IMAGE_HEIGHT);
        IMAGE_WIDTH = checkResolution.cols;
        IMAGE_HEIGHT = checkResolution.rows;
    }
    setFixedSize(IMAGE_WIDTH, IMAGE_HEIGHT);
}

void ImageView::paintEvent(QPaintEvent *)
{
    if (curImage.empty()) {
        return;
    }
    QPainter painter(this);
    
    painter.drawImage(0, 0, QImg);

    m_Object.clear();
    char str[100];
    int pos_ = imageName[currentIndex].find_last_of(".");
    sprintf(str, "%s%s.ano", resultDir.c_str(), imageName[currentIndex].substr(0,pos_).c_str());
    std::ifstream inf(str);

    if (inf.is_open()) {
        int type, x, y, w, h;
        inf >> type;
        while(!inf.eof()){
            inf >> x >> y >> w >> h;
            m_Object.push_back(detectObject((objectType)type, QRect(x, y, w, h)));
            inf >> type;
        }
    }
    inf.close();

    if (showAll)
    {
        if (m_Object.size()){
            for(size_t i = 0; i<m_Object.size(); i++){
                int index_ = m_Object[i].getType();
                QPen pen(QColor(m_ocl[index_].r, m_ocl[index_].g, m_ocl[index_].b),
                         3, Qt::DashDotLine, Qt::RoundCap, Qt::RoundJoin);
                painter.setPen(pen);
                painter.drawRect(m_Object[i].getPos());
            }
        }

        if (m_Rect.size()) {
            painter.setBrush(Qt::DiagCrossPattern);
            for (size_t i = 0; i < m_Rect.size(); i++){
                int index_ = m_Rect[i].getType();
                QPen pen(QColor(m_ocl[index_].r, m_ocl[index_].g, m_ocl[index_].b),
                         3, Qt::DashDotLine, Qt::RoundCap, Qt::RoundJoin);
                painter.setPen(pen);
                painter.drawRect(m_Rect[i].getPos());
            }
        }
    }

    else // only show one type
    {
        QPen pen(QColor(m_ocl[currentType].r, m_ocl[currentType].g, m_ocl[currentType].b), 3, Qt::DashDotLine, Qt::RoundCap, Qt::RoundJoin);
        painter.setPen(pen);
        if(m_Object.size()){
            for(size_t i = 0;i<m_Object.size();i++){
                if(m_Object[i].getType()==currentType)
                    painter.drawRect(m_Object[i].getPos());
            }
        }

        if(m_Rect.size()){
            painter.setBrush(Qt::DiagCrossPattern);
            for(size_t i = 0;i<m_Rect.size();i++){
                if(m_Rect[i].getType()==currentType)
                    painter.drawRect(m_Rect[i].getPos());
            }
        }
    }// end of if(showAll)
}

void ImageView::mousePressEvent(QMouseEvent *event)
{
    if(Qt::LeftButton == event->button())
    {
        QRect tmpRect;
        tmpRect.setTopLeft(event->pos());
        if(event->pos().x()>0 && event->pos().y()>0)
            m_Rect.push_back(detectObject(currentType,tmpRect));
    }

    else if(Qt::RightButton == event->button()){
        char str[48];
        sprintf(str,"%s%s.ano",resultDir.c_str(),imageName[currentIndex].substr(0,8).c_str());
        std::ifstream inf(str);

        if(!inf.is_open())
            return ;

        //        int nCount = 0;
        std::vector<detectObject>  tempVec;
        tempVec.clear();
        bool needRemove = false;
        int type,x,y,w,h;
        inf>>type;
        while(!inf.eof()){
            inf>>x>>y>>w>>h;
            if(type==currentType && x<=event->pos().x() &&
                    y<=event->pos().y() && (x+w)>event->pos().x() && (y+h)>event->pos().y())
            {
                needRemove = true;
                inf>>type;
                continue;
            }

            tempVec.push_back(detectObject(type,QRect(x,y,w,h)));
            inf >> type;
        }
        inf.close();

        if (needRemove)
        {
            if(tempVec.size()){
                char dest[48];
                 int pos_ = imageName[currentIndex].find_last_of(".");
                sprintf(dest,"%s%s.ano.tmp",resultDir.c_str(),imageName[currentIndex].substr(0,pos_).c_str());
                std::ofstream out(dest);
                if(out.is_open())
                {
                    for(std::vector<detectObject>::iterator iter=tempVec.begin();iter!=tempVec.end();iter++)
                        out<<iter->getType()<<" "<<iter->getPos().topLeft().x()<<" "<<iter->getPos().topLeft().y()
                          <<" "<<iter->getPos().width()<<" "<<iter->getPos().height()<<"\n";

                    out.close();
                    remove(str);   rename(dest,str);
                    update();
                }
                else {
                    printf("Err: Can't touch a temp file!\n");
                    exit(-2);
                }
            }
            else {remove(str); update();}
        }
    }
}

void ImageView::mouseReleaseEvent(QMouseEvent *event)
{
    if (Qt::LeftButton == event->button()) {
        detectObject &tmpRect = m_Rect.back();
        /**  tmpRect.getPos().topLeft.x()<event->pos().x()?
         *      tmpRect.getPos().topLeft.x():event->pos().x();
         *   detectObject tempObj(tmpRect.getType(),());
         */
        QPoint tempPoint = event->pos();
        if (tempPoint.x() > IMAGE_WIDTH-1) tempPoint.setX(IMAGE_WIDTH-1);
        if (tempPoint.y() > IMAGE_HEIGHT-1) tempPoint.setX(IMAGE_HEIGHT-1);

        tmpRect.getPos().setBottomRight(tempPoint);

        if (tempPoint.x() < 0 || tempPoint.y() < 0 || tempPoint.x() < tmpRect.getPos().topLeft().x() ||
            tempPoint.y() < tmpRect.getPos().topLeft().y() || tmpRect.getPos().width() < 10 ||
            tmpRect.getPos().height() < 10) {
            m_Rect.pop_back();
            return;
        }

        update();
    }
}

void ImageView::keyPressEvent(QKeyEvent *event)
{
    switch (event->key()) {
    case Qt::Key_Up: case Qt::Key_Left:
    case Qt::Key_Down: case Qt::Key_Right:
        if (event->isAutoRepeat()) return;
        savePoint();
        m_Rect.clear();
        if (event->key() == Qt::Key_Up || event->key() == Qt::Key_Left) {
            --currentIndex;
        } else {
            ++currentIndex;
        }
        break;

    case Qt::Key_Z:
        if (event->modifiers() == Qt::ControlModifier){
            if (m_Rect.size()) {
                if (currentType == m_Rect.back().getType())
                    m_Rect.pop_back();
                else {
#ifdef _WIN32
                    set_console_default_color();
                    printf("Warnning: New draw is not ");
                    set_console_color(BACKGROUND_BLUE|BACKGROUND_GREEN);
                    printf("%s!\n",m_ocl[currentType].name.c_str());
#endif
#ifdef __linux__
	printf("Warnning: New draw is not \033[1;32;40m %s!\033[0m\n",m_ocl[currentType].name.c_str());
#endif
                }
            }
            else printf("Warnning: Without new draw!\n");

        }
        update();
        break;
    case Qt::Key_Escape:
        printf("Bye-bye!\n");
        emit finished_exit();
        break;
    default:
        return;
    }
    if (currentIndex == imageName.size())  currentIndex = 0;
    else if (currentIndex < 0)             currentIndex = imageName.size() - 1;

    setImage();
    emit currentIndexChanged(currentIndex % totalLine);
}

void ImageView::savePoint()
{
    char str[100];
    int pos_ = imageName[currentIndex].find_last_of(".");
    sprintf(str, "%s%s.ano", resultDir.c_str(), imageName[currentIndex].substr(0,pos_).c_str());

    if (m_Rect.size()) {
        std::ofstream out(str, std::ios::app);
        if (out.is_open())
        {
            for (size_t var = 0; var < m_Rect.size(); ++var) {
                out << m_Rect[var].getType() << " " << m_Rect[var].getPos().topLeft().x() << " "
                    << m_Rect[var].getPos().topLeft().y() << " " << m_Rect[var].getPos().width()
                    << " " << m_Rect[var].getPos().height() << "\n";
            }
        }
        out.close();
    }
}

void ImageView::Refresh(cv::Mat &input)
{
    curImage = input.clone();
    update();
}

void ImageView::reLoadData()
{
    needReload = true;
}
